#include "EPubDocumentImp.h"

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>

#include "ZipUtility\zip.h"
#include "ZipUtility\unzip.h"

#include "EPubBasicMimeTypeImp.h"
#include "EPubBasicContainerImp.h"
#include "EPubBasicEncryptionImp.h"
#include "EPubBasicRootImp.h"

#include "EPubMediaXHtmlImp.h"
#include "EPubMediaJPEGImp.h"
#include "EPubMediaOPF2Imp.h"
#include "EPubMediaStyleSheetImp.h"
#include "EPubUtil.h"

EPUB_Result EPubDocumentImp::Load(const char *path)
{
	EPUB_Result		ret = EPUB_SUCCESS;
	HZIP			hZip = NULL;
	ZRESULT			zRet = ZR_OK;
	ZIPENTRY		zEntry = { 0 };
	int				nFileCount = 0;
	FILE *			file = NULL;

	hZip = OpenZip(path, NULL);

	// Get total count.
	zRet = GetZipItem(hZip, -1, &zEntry);
	nFileCount = zEntry.index;

	for(int i = 0; i < nFileCount; ++i) {

		// Get file item.
		if(GetZipItem(hZip, i, &zEntry) != ZR_OK
		   || zEntry.unc_size == 0
		   || zEntry.comp_size == 0)
		{
			continue;
		}

		EPubPointer<EPubBufferImp> item_buffer(new EPubBufferImp(zEntry.unc_size));

		// Uncompress file.
		if(UnzipItem(hZip, i, item_buffer->UseBuffer(), zEntry.unc_size) != ZR_OK) {
			continue;
		}

		m_FileBufferList[zEntry.name] = item_buffer;
	}

	CloseZip(hZip);

	return ret;
}

EPUB_Result EPubDocumentImp::Save(const char *path) const
{
	EPUB_Result		ret = EPUB_SUCCESS;
	HZIP			hZip = NULL;
	ZRESULT			zRet = ZR_OK;

	hZip = CreateZip(path, NULL);

	for(EPubFileBufferList::const_iterator iter = m_FileBufferList.begin();
		iter != m_FileBufferList.end();
		++iter)
	{
		zRet = ZipAdd(hZip,
					  iter->first.c_str(),
					  (void *)iter->second->GetBuffer(),
					  iter->second->GetBufferSize());
	}

	CloseZip(hZip);
	return ret;
}

const EPubPointer<IEPubBuffer> EPubDocumentImp::GetFileBuffer(const char *href) const
{
	EPUB_Result ret = EPUB_SUCCESS;

	EPubFileBufferList::const_iterator pos = m_FileBufferList.find(href);
	if(pos == m_FileBufferList.end()) {
		return NULL;
	}

	return pos->second.Cast<IEPubBuffer>();
}

const EPubPointer<IEPubBuffer> EPubDocumentImp::GetBasicFileBuffer(EPUB_BasicFileType basicFileType) const
{
	switch(basicFileType) {
	case EPUB_BFT_MIME_TYPE:
		return GetFileBuffer(EPUB_BFP_MIME_TYPE);
	case EPUB_BFT_META_INF_CONTAINER:
		return GetFileBuffer(EPUB_BFP_META_INF_CONTAINER);
	case EPUB_BFT_META_INF_ENCRYPTION:
		return GetFileBuffer(EPUB_BFP_META_INF_ENCRYPTION);
	case EPUB_BFT_ROOT:
		{
			const EPubPointer<IEPubBuffer> buffer_container = GetBasicFileBuffer(EPUB_BFT_META_INF_CONTAINER);
			EPubPointer<IEPubBasicContainer> container = CreateBasicFile(EPUB_BFT_META_INF_CONTAINER).Cast<IEPubBasicContainer>();
			container->Deserialize(buffer_container);
			return GetFileBuffer(container->GetRootFile());
		}
		break;
	default:
		return NULL;
	}
	return NULL;
}

EPubPointer<IEPubBasic> IEPubDocument::CreateBasicFile(EPUB_BasicFileType basicFileType)
{
	IEPubBasic *basic_file = NULL;

	switch(basicFileType) {
	case EPUB_BFT_MIME_TYPE:
		basic_file = new EPubBasicMimeTypeImp;
		break;
	case EPUB_BFT_META_INF_CONTAINER:
		basic_file = new EPubBasicContainerImp;
		break;
	case EPUB_BFT_META_INF_ENCRYPTION:
		basic_file = new EPubBasicEncryptionImp;
		break;
	case EPUB_BFT_ROOT:
		basic_file = new EPubBasicRootImp;
		break;
	default:
		break;
	}
	return basic_file;
}

EPubPointer<IEPubMedia> IEPubDocument::CreateMediaFile(EPUB_MediaFileType mediaFileType)
{
	IEPubMedia *media_file = NULL;
	switch(mediaFileType){
	case EPUB_MFT_GIF:
		break;
	case EPUB_MFT_JPEG:
		media_file = new EPubMediaJPEGImp;
		break;
	case EPUB_MFT_PNG:
		break;
	case EPUB_MFT_SVG:
		break;
	case EPUB_MFT_XHTML:
		media_file = new EPubMediaXHtmlImp;
		break;
	case EPUB_MFT_OPF2:
		media_file = new EPubMediaOPF2Imp;
		break;
	case EPUB_MFT_OPEN_TYPE:
		break;
	case EPUB_MFT_WOFF:
		break;
	case EPUB_MFT_MEDIA_OVERLAYS:
		break;
	case EPUB_MFT_PLS:
		break;
	case EPUB_MFT_MP3:
		break;
	case EPUB_MFT_MP4:
		break;
	case EPUB_MFT_STYLE_SHEETS:
		media_file = new EPubMediaStyleSheetImp;
		break;
	case EPUB_MFT_JAVASCRIPT:
		break;
	default:
		break;
	}
	return media_file;
}

EPUB_MediaFileType IEPubDocument::ToMediaFileType(const char *mediaType)
{
	std::string media_type(mediaType);

	if(media_type.compare(EPUB_MT_GIF) == 0) {
		return EPUB_MFT_GIF;
	} else if(media_type.compare(EPUB_MT_JPEG) == 0) {
		return EPUB_MFT_JPEG;
	} else if(media_type.compare(EPUB_MT_PNG) == 0) {
		return EPUB_MFT_PNG;
	} else if(media_type.compare(EPUB_MT_SVG) == 0) {
		return EPUB_MFT_SVG;
	} else if(media_type.compare(EPUB_MT_XHTML) == 0) {
		return EPUB_MFT_XHTML;
	} else if(media_type.compare(EPUB_MT_OPF2) == 0) {
		return EPUB_MFT_OPF2;
	} else if(media_type.compare(EPUB_MT_OPEN_TYPE) == 0) {
		return EPUB_MFT_OPEN_TYPE;
	} else if(media_type.compare(EPUB_MT_WOFF) == 0) {
		return EPUB_MFT_WOFF;
	} else if(media_type.compare(EPUB_MT_MEDIA_OVERLAYS) == 0) {
		return EPUB_MFT_MEDIA_OVERLAYS;
	} else if(media_type.compare(EPUB_MT_PLS) == 0) {
		return EPUB_MFT_PLS;
	} else if(media_type.compare(EPUB_MT_MP3) == 0) {
		return EPUB_MFT_MP3;
	} else if(media_type.compare(EPUB_MT_MP4) == 0) {
		return EPUB_MFT_MP4;
	} else if(media_type.compare(EPUB_MT_STYLE_SHEETS) == 0) {
		return EPUB_MFT_STYLE_SHEETS;
	} else if(media_type.compare(EPUB_MT_JAVASCRIPT) == 0) {
		return EPUB_MFT_JAVASCRIPT;
	}

	return EPUB_MFT_UNKNOWN;
}

const char *IEPubDocument::ToMediaType(EPUB_MediaFileType mediaFileType)
{
	switch(mediaFileType) {
	case EPUB_MFT_GIF:
		return EPUB_MT_GIF;
	case EPUB_MFT_JPEG:
		return EPUB_MT_JPEG;
	case EPUB_MFT_PNG:
		return EPUB_MT_PNG;
	case EPUB_MFT_SVG:
		return EPUB_MT_SVG;
	case EPUB_MFT_XHTML:
		return EPUB_MT_XHTML;
	case EPUB_MFT_OPF2:
		return EPUB_MT_OPF2;
	case EPUB_MFT_OPEN_TYPE:
		return EPUB_MT_OPEN_TYPE;
	case EPUB_MFT_WOFF:
		return EPUB_MT_WOFF;
	case EPUB_MFT_MEDIA_OVERLAYS:
		return EPUB_MT_MEDIA_OVERLAYS;
	case EPUB_MFT_PLS:
		return EPUB_MT_PLS;
	case EPUB_MFT_MP3:
		return EPUB_MT_MP3;
	case EPUB_MFT_MP4:
		return EPUB_MT_MP4;
	case EPUB_MFT_STYLE_SHEETS:
		return EPUB_MT_STYLE_SHEETS;
	case EPUB_MFT_JAVASCRIPT:
		return EPUB_MT_JAVASCRIPT;
	default:
		return "";
	}
}